mirror of
https://codeberg.org/icewind/single-file-server.git
synced 2026-06-03 18:14:09 +02:00
listenfd support
This commit is contained in:
parent
9fbe3bf7fc
commit
0f3ac7ebd1
6 changed files with 130 additions and 10 deletions
96
Cargo.lock
generated
96
Cargo.lock
generated
|
|
@ -148,6 +148,12 @@ dependencies = [
|
||||||
"windows-targets",
|
"windows-targets",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bumpalo"
|
||||||
|
version = "3.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
version = "1.10.1"
|
version = "1.10.1"
|
||||||
|
|
@ -381,6 +387,16 @@ version = "1.0.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "js-sys"
|
||||||
|
version = "0.3.77"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
|
||||||
|
dependencies = [
|
||||||
|
"once_cell",
|
||||||
|
"wasm-bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
|
|
@ -393,6 +409,17 @@ version = "0.2.174"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
|
checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "listenfd"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b87bc54a4629b4294d0b3ef041b64c40c611097a677d9dc07b2c67739fe39dba"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"uuid",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.27"
|
version = "0.4.27"
|
||||||
|
|
@ -621,6 +648,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"axum",
|
"axum",
|
||||||
"clap",
|
"clap",
|
||||||
|
"listenfd",
|
||||||
"main_error",
|
"main_error",
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
|
|
@ -864,6 +892,16 @@ version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uuid"
|
||||||
|
version = "1.17.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d"
|
||||||
|
dependencies = [
|
||||||
|
"js-sys",
|
||||||
|
"wasm-bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "valuable"
|
name = "valuable"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
|
|
@ -876,6 +914,64 @@ version = "0.11.1+wasi-snapshot-preview1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen"
|
||||||
|
version = "0.2.100"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"once_cell",
|
||||||
|
"rustversion",
|
||||||
|
"wasm-bindgen-macro",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-backend"
|
||||||
|
version = "0.2.100"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
|
||||||
|
dependencies = [
|
||||||
|
"bumpalo",
|
||||||
|
"log",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"wasm-bindgen-shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-macro"
|
||||||
|
version = "0.2.100"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
|
||||||
|
dependencies = [
|
||||||
|
"quote",
|
||||||
|
"wasm-bindgen-macro-support",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-macro-support"
|
||||||
|
version = "0.2.100"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"wasm-bindgen-backend",
|
||||||
|
"wasm-bindgen-shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-shared"
|
||||||
|
version = "0.2.100"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.3.9"
|
version = "0.3.9"
|
||||||
|
|
|
||||||
|
|
@ -13,3 +13,4 @@ serde = { version = "1.0.219", features = ["derive"] }
|
||||||
toml = "0.8.23"
|
toml = "0.8.23"
|
||||||
thiserror = "2.0.12"
|
thiserror = "2.0.12"
|
||||||
clap = { version = "4.5.40", features = ["derive"] }
|
clap = { version = "4.5.40", features = ["derive"] }
|
||||||
|
listenfd = "1.0.2"
|
||||||
|
|
@ -11,7 +11,7 @@ A basic web server for
|
||||||
# address = "0.0.0.0" # defaults to "127.0.0.1"
|
# address = "0.0.0.0" # defaults to "127.0.0.1"
|
||||||
# port = 1234 # defaults to 7366
|
# port = 1234 # defaults to 7366
|
||||||
# you can set it to listen over a unix socket instead.
|
# you can set it to listen over a unix socket instead.
|
||||||
socket = "/var/run/single-file.sock"
|
socket = "/run/single-file.sock"
|
||||||
|
|
||||||
[single-file]
|
[single-file]
|
||||||
# path to single-file-cli
|
# path to single-file-cli
|
||||||
|
|
@ -22,6 +22,10 @@ executable = "/path/to/single-file" # defaults to "single-file"
|
||||||
executable = "/path/to/chome" # defaults to "chromium"
|
executable = "/path/to/chome" # defaults to "chromium"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
In additional to the `listen` configuration, the server will automatically
|
||||||
|
detect if it get's activated trough systemd socket activation and takes the
|
||||||
|
provided socket.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ use toml::from_str;
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub listen: ListenConfig,
|
pub listen: ListenConfig,
|
||||||
#[serde(default)]
|
#[serde(default, rename = "single-file")]
|
||||||
pub single_file: SingleFileConfig,
|
pub single_file: SingleFileConfig,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub browser: BrowserConfig,
|
pub browser: BrowserConfig,
|
||||||
|
|
|
||||||
11
src/fetch.rs
11
src/fetch.rs
|
|
@ -4,7 +4,7 @@ use axum::http::StatusCode;
|
||||||
use axum::response::{IntoResponse, Response};
|
use axum::response::{IntoResponse, Response};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tokio::task::{JoinError, spawn_blocking};
|
use tokio::task::{JoinError, spawn_blocking};
|
||||||
use tracing::info;
|
use tracing::{debug, info, warn};
|
||||||
|
|
||||||
pub async fn fetch_single_file(config: &Config, url: &str) -> Result<String, FetchError> {
|
pub async fn fetch_single_file(config: &Config, url: &str) -> Result<String, FetchError> {
|
||||||
info!(url, "fetching url");
|
info!(url, "fetching url");
|
||||||
|
|
@ -20,9 +20,16 @@ pub async fn fetch_single_file(config: &Config, url: &str) -> Result<String, Fet
|
||||||
|
|
||||||
command.arg(url).arg("--dump-content");
|
command.arg(url).arg("--dump-content");
|
||||||
|
|
||||||
|
debug!(?command, "running single-file command");
|
||||||
|
|
||||||
let output = spawn_blocking(move || command.output().map_err(FetchError::Command)).await??;
|
let output = spawn_blocking(move || command.output().map_err(FetchError::Command)).await??;
|
||||||
|
|
||||||
Ok(String::from_utf8_lossy(&output.stdout).to_string())
|
if !output.stderr.is_empty() {
|
||||||
|
warn!(output = %String::from_utf8_lossy(&output.stderr), "command returned stderr");
|
||||||
|
}
|
||||||
|
let result = String::from_utf8_lossy(&output.stdout).to_string();
|
||||||
|
debug!(length = result.len(), status = ?output.status.code().unwrap_or_default(), "single-file done");
|
||||||
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
|
|
|
||||||
22
src/main.rs
22
src/main.rs
|
|
@ -9,10 +9,12 @@ use axum::{debug_handler, Router};
|
||||||
use axum::extract::{Path, State};
|
use axum::extract::{Path, State};
|
||||||
use axum::routing::get;
|
use axum::routing::get;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
use listenfd::ListenFd;
|
||||||
use main_error::MainResult;
|
use main_error::MainResult;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tokio::net::UnixListener;
|
use tokio::net::UnixListener;
|
||||||
use tokio::signal::ctrl_c;
|
use tokio::signal::ctrl_c;
|
||||||
|
use tracing::error;
|
||||||
use crate::config::{Config, ListenConfig};
|
use crate::config::{Config, ListenConfig};
|
||||||
use crate::fetch::{fetch_single_file, FetchError};
|
use crate::fetch::{fetch_single_file, FetchError};
|
||||||
|
|
||||||
|
|
@ -46,8 +48,18 @@ async fn main() -> MainResult {
|
||||||
ctrl_c().await.ok();
|
ctrl_c().await.ok();
|
||||||
};
|
};
|
||||||
|
|
||||||
match &config.listen {
|
let mut systemd_listener = ListenFd::from_env();
|
||||||
ListenConfig::Unix { socket: path } => {
|
|
||||||
|
match (systemd_listener.take_unix_listener(0), &config.listen) {
|
||||||
|
(Ok(Some(listener)), _) => {
|
||||||
|
println!("listening on fd 0");
|
||||||
|
let listener = UnixListener::from_std(listener).unwrap();
|
||||||
|
axum::serve(listener, app)
|
||||||
|
.with_graceful_shutdown(cancel)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
(_, ListenConfig::Unix { socket: path }) => {
|
||||||
if let Some(parent) = path.parent() {
|
if let Some(parent) = path.parent() {
|
||||||
if !parent.exists() {
|
if !parent.exists() {
|
||||||
create_dir_all(parent)
|
create_dir_all(parent)
|
||||||
|
|
@ -60,7 +72,7 @@ async fn main() -> MainResult {
|
||||||
|
|
||||||
let uds = UnixListener::bind(path)
|
let uds = UnixListener::bind(path)
|
||||||
.map_err(|error| SetupError::BindUnix { error, path: path.clone() })?;
|
.map_err(|error| SetupError::BindUnix { error, path: path.clone() })?;
|
||||||
let _ = set_permissions(path, PermissionsExt::from_mode(0o660));
|
let _ = set_permissions(path, PermissionsExt::from_mode(0o666));
|
||||||
|
|
||||||
|
|
||||||
println!("listening on {}", path.display());
|
println!("listening on {}", path.display());
|
||||||
|
|
@ -70,7 +82,7 @@ async fn main() -> MainResult {
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
ListenConfig::Tcp {address, port} => {
|
(_, ListenConfig::Tcp {address, port}) => {
|
||||||
let address = SocketAddr::new(*address, *port);
|
let address = SocketAddr::new(*address, *port);
|
||||||
let listener = tokio::net::TcpListener::bind(address).await
|
let listener = tokio::net::TcpListener::bind(address).await
|
||||||
.map_err(|error| SetupError::BindTcp { error, address })?;
|
.map_err(|error| SetupError::BindTcp { error, address })?;
|
||||||
|
|
@ -112,6 +124,6 @@ enum SetupError {
|
||||||
|
|
||||||
#[debug_handler]
|
#[debug_handler]
|
||||||
async fn fetch(State(state): State<App>, Path(url): Path<String>) -> Result<String, FetchError> {
|
async fn fetch(State(state): State<App>, Path(url): Path<String>) -> Result<String, FetchError> {
|
||||||
fetch_single_file(state.config, &url).await
|
fetch_single_file(state.config, &url).await.inspect_err(|error| error!(%error, url, "Error while fetching url"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue