Added Reload on SIGHUP
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -186,7 +186,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gemserv"
|
name = "gemserv"
|
||||||
version = "0.6.2"
|
version = "0.6.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"log",
|
"log",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "gemserv"
|
name = "gemserv"
|
||||||
version = "0.6.2"
|
version = "0.6.3"
|
||||||
authors = ["int 80h <int@80h.dev>"]
|
authors = ["int 80h <int@80h.dev>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
description = "A gemini server"
|
description = "A gemini server"
|
||||||
|
|||||||
13
README
13
README
@@ -10,21 +10,26 @@ A gemini server written in rust.
|
|||||||
- Reverse proxy
|
- Reverse proxy
|
||||||
- Redirect
|
- Redirect
|
||||||
- SCGI
|
- SCGI
|
||||||
|
- Reload config on SIGHUP
|
||||||
|
|
||||||
## Installation and running
|
## Installation and running
|
||||||
|
|
||||||
To run either run "cargo run /path/to/config" or if no configuration is
|
To run either run "cargo run /path/to/config" or if no configuration is
|
||||||
specified it will look for "/usr/local/etc/gemserv.conf"
|
specified it will look for "/usr/local/etc/gemserv.conf"
|
||||||
|
|
||||||
## Install from crates.io:
|
### Prebuilt binaries
|
||||||
|
|
||||||
|
You can download prebuilt binaries for linux on the release page.
|
||||||
|
|
||||||
|
### Install from crates.io:
|
||||||
|
|
||||||
cargo install gemserv
|
cargo install gemserv
|
||||||
|
|
||||||
## Install from docker
|
### Install from docker
|
||||||
|
|
||||||
docker pull 080h/gemserv
|
docker pull 080h/gemserv
|
||||||
|
|
||||||
## Build from source:
|
### Build from source:
|
||||||
|
|
||||||
- Clone the repo
|
- Clone the repo
|
||||||
- If you want to use all features run 'cargo build --release' or if you only
|
- If you want to use all features run 'cargo build --release' or if you only
|
||||||
@@ -32,7 +37,7 @@ docker pull 080h/gemserv
|
|||||||
- Modify the config.toml to your needs
|
- Modify the config.toml to your needs
|
||||||
- Run './target/release/gemserv config.toml'
|
- Run './target/release/gemserv config.toml'
|
||||||
|
|
||||||
### Init scripts
|
## Init scripts
|
||||||
|
|
||||||
In the init-scripts directory there's OpenRC(Courtesy of Tastytea) and systemd
|
In the init-scripts directory there's OpenRC(Courtesy of Tastytea) and systemd
|
||||||
service files.
|
service files.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use tokio::fs::{self, File};
|
|
||||||
use tokio::io::{self, BufReader, AsyncWrite, AsyncBufReadExt};
|
|
||||||
use std::os::unix::fs::PermissionsExt;
|
use std::os::unix::fs::PermissionsExt;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
use tokio::fs::{self, File};
|
||||||
|
use tokio::io::{self, AsyncBufReadExt, AsyncWrite, BufReader};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
#[cfg(any(feature = "cgi", feature = "scgi"))]
|
#[cfg(any(feature = "cgi", feature = "scgi"))]
|
||||||
@@ -36,7 +36,8 @@ fn get_mime(path: &Path) -> String {
|
|||||||
async fn get_binary(mut con: conn::Connection, path: PathBuf, meta: String) -> io::Result<()> {
|
async fn get_binary(mut con: conn::Connection, path: PathBuf, meta: String) -> io::Result<()> {
|
||||||
let fd = File::open(path).await?;
|
let fd = File::open(path).await?;
|
||||||
let mut reader = BufReader::with_capacity(1024 * 1024, fd);
|
let mut reader = BufReader::with_capacity(1024 * 1024, fd);
|
||||||
con.send_raw(format!("{} {}\r\n", Status::Success as u8, &meta).as_bytes()).await?;
|
con.send_raw(format!("{} {}\r\n", Status::Success as u8, &meta).as_bytes())
|
||||||
|
.await?;
|
||||||
loop {
|
loop {
|
||||||
let len = {
|
let len = {
|
||||||
let buf = reader.fill_buf().await?;
|
let buf = reader.fill_buf().await?;
|
||||||
@@ -49,9 +50,7 @@ async fn get_binary(mut con: conn::Connection, path: PathBuf, meta: String) -> i
|
|||||||
reader.consume(len);
|
reader.consume(len);
|
||||||
}
|
}
|
||||||
|
|
||||||
futures_util::future::poll_fn(|ctx| {
|
futures_util::future::poll_fn(|ctx| std::pin::Pin::new(&mut con.stream).poll_shutdown(ctx))
|
||||||
std::pin::Pin::new(&mut con.stream).poll_shutdown(ctx)
|
|
||||||
})
|
|
||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -202,7 +201,7 @@ pub async fn handle_connection(mut con: conn::Connection, url: url::Url) -> Resu
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,18 +318,15 @@ pub async fn handle_connection(mut con: conn::Connection, url: url::Url) -> Resu
|
|||||||
}
|
}
|
||||||
match fs::read_to_string(path).await {
|
match fs::read_to_string(path).await {
|
||||||
Ok(c) => {
|
Ok(c) => {
|
||||||
con.send_body(Status::Success, Some(&mime), Some(c))
|
con.send_body(Status::Success, Some(&mime), Some(c)).await?;
|
||||||
.await?;
|
|
||||||
logger::logger(con.peer_addr, Status::Success, url.as_str());
|
logger::logger(con.peer_addr, Status::Success, url.as_str());
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("{}", e);
|
println!("{}", e);
|
||||||
con.send_status(Status::NotFound, None)
|
con.send_status(Status::NotFound, None).await?;
|
||||||
.await?;
|
|
||||||
logger::logger(con.peer_addr, Status::NotFound, url.as_str());
|
logger::logger(con.peer_addr, Status::NotFound, url.as_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
let dir = gen_dir_list(path, &url).await?;
|
let dir = gen_dir_list(path, &url).await?;
|
||||||
con.send_body(Status::Success, Some(&mime), Some(dir))
|
con.send_body(Status::Success, Some(&mime), Some(dir))
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ extern crate toml;
|
|||||||
use crate::lib::errors;
|
use crate::lib::errors;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::path;
|
|
||||||
use std::net;
|
use std::net;
|
||||||
use std::net::ToSocketAddrs;
|
use std::net::ToSocketAddrs;
|
||||||
|
use std::path;
|
||||||
use tokio::fs;
|
use tokio::fs;
|
||||||
use tokio::io;
|
use tokio::io;
|
||||||
|
|
||||||
@@ -91,7 +91,11 @@ impl Config {
|
|||||||
} else if config.host.is_some() && config.port.is_some() {
|
} else if config.host.is_some() && config.port.is_some() {
|
||||||
let mut addr: Vec<std::net::SocketAddr> = Vec::new();
|
let mut addr: Vec<std::net::SocketAddr> = Vec::new();
|
||||||
addr.push(
|
addr.push(
|
||||||
format!("{}:{}", &config.host.to_owned().unwrap(), &config.port.unwrap())
|
format!(
|
||||||
|
"{}:{}",
|
||||||
|
&config.host.to_owned().unwrap(),
|
||||||
|
&config.port.unwrap()
|
||||||
|
)
|
||||||
.to_socket_addrs()?
|
.to_socket_addrs()?
|
||||||
.next()
|
.next()
|
||||||
.ok_or_else(|| io::Error::from(io::ErrorKind::AddrNotAvailable))?,
|
.ok_or_else(|| io::Error::from(io::ErrorKind::AddrNotAvailable))?,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#![allow(unreachable_code)]
|
#![allow(unreachable_code)]
|
||||||
use tokio::io::AsyncReadExt;
|
use tokio::io::AsyncReadExt;
|
||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
|
use tokio::sync::watch::Receiver;
|
||||||
use tokio_rustls::server::TlsStream;
|
use tokio_rustls::server::TlsStream;
|
||||||
use tokio_rustls::TlsAcceptor;
|
use tokio_rustls::TlsAcceptor;
|
||||||
|
|
||||||
@@ -71,15 +72,21 @@ impl Server {
|
|||||||
self,
|
self,
|
||||||
cmap: HashMap<String, config::ServerCfg>,
|
cmap: HashMap<String, config::ServerCfg>,
|
||||||
handler: impl Handler + 'static + Copy,
|
handler: impl Handler + 'static + Copy,
|
||||||
|
shutdown: Receiver<bool>,
|
||||||
) -> Result {
|
) -> Result {
|
||||||
for listen in self.listener {
|
for listen in self.listener {
|
||||||
let cmap = cmap.clone();
|
let cmap = cmap.clone();
|
||||||
let listen = Arc::new(listen);
|
let listen = Arc::new(listen);
|
||||||
let acceptor = Arc::new(self.acceptor.clone());
|
let acceptor = Arc::new(self.acceptor.clone());
|
||||||
|
let mut shutdown = shutdown.clone();
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
loop {
|
loop {
|
||||||
let (stream, peer_addr) = listen.accept().await?;
|
tokio::select! {
|
||||||
|
_ = shutdown.changed() => {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
Ok((stream, peer_addr)) = listen.accept() => {
|
||||||
let local_addr = stream.local_addr().unwrap();
|
let local_addr = stream.local_addr().unwrap();
|
||||||
let acceptor = acceptor.clone();
|
let acceptor = acceptor.clone();
|
||||||
let cmap = cmap.clone();
|
let cmap = cmap.clone();
|
||||||
@@ -121,15 +128,14 @@ impl Server {
|
|||||||
Err(_) => return Ok(()) as io::Result<()>,
|
Err(_) => return Ok(()) as io::Result<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(()) as io::Result<()>
|
Ok(())
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Ok(()) as io::Result<()>
|
}
|
||||||
|
}
|
||||||
|
Ok(()) as Result
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
tokio::signal::ctrl_c()
|
|
||||||
.await
|
|
||||||
.expect("failed to listen for event");
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,10 @@ pub fn init(loglev: &Option<String>) -> errors::Result {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
simple_logger::SimpleLogger::new().with_level(loglev).with_utc_timestamps().init().unwrap();
|
simple_logger::SimpleLogger::new()
|
||||||
|
.with_level(loglev)
|
||||||
|
.with_utc_timestamps()
|
||||||
|
.init()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
50
src/main.rs
50
src/main.rs
@@ -17,8 +17,11 @@ use lib::status;
|
|||||||
use lib::tls::{self, tls_acceptor_conf};
|
use lib::tls::{self, tls_acceptor_conf};
|
||||||
use lib::util;
|
use lib::util;
|
||||||
|
|
||||||
#[tokio::main]
|
use tokio::signal::unix;
|
||||||
async fn main() -> errors::Result {
|
use tokio::sync::watch;
|
||||||
|
|
||||||
|
async fn run(mut recv: watch::Receiver<bool>) -> errors::Result {
|
||||||
|
loop {
|
||||||
let cfg = match config::Config::new().await {
|
let cfg = match config::Config::new().await {
|
||||||
Ok(c) => c,
|
Ok(c) => c,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@@ -27,10 +30,13 @@ async fn main() -> errors::Result {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
logger::init(&cfg.log)?;
|
// This will error because log init only wants to be called once.
|
||||||
|
// On reload it will allow going from higher to lower logging levels
|
||||||
|
// however trying to go from a lower lever to higher won't change.
|
||||||
|
if let Err(_) = logger::init(&cfg.log) {}
|
||||||
|
|
||||||
let cmap = cfg.to_map();
|
let cmap = cfg.to_map();
|
||||||
println!("Serving {} vhosts", cfg.server.len());
|
log::info!("Serving {} vhosts", cfg.server.len());
|
||||||
|
|
||||||
let mut addr: Vec<std::net::SocketAddr> = Vec::new();
|
let mut addr: Vec<std::net::SocketAddr> = Vec::new();
|
||||||
if let Some(i) = &cfg.interface {
|
if let Some(i) = &cfg.interface {
|
||||||
@@ -42,10 +48,46 @@ async fn main() -> errors::Result {
|
|||||||
.serve(
|
.serve(
|
||||||
cmap,
|
cmap,
|
||||||
server::force_boxed(con_handler::handle_connection),
|
server::force_boxed(con_handler::handle_connection),
|
||||||
|
recv.clone(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
return Err(e);
|
return Err(e);
|
||||||
};
|
};
|
||||||
|
recv.changed().await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn signal_select(send: watch::Sender<bool>) -> errors::Result {
|
||||||
|
let mut hangup = unix::signal(unix::SignalKind::hangup())?;
|
||||||
|
let mut sigterm = unix::signal(unix::SignalKind::terminate())?;
|
||||||
|
loop {
|
||||||
|
tokio::select! {
|
||||||
|
_ = tokio::signal::ctrl_c() => {
|
||||||
|
log::info!("Received ctrl-c shutting down!");
|
||||||
|
send.send(false)?;
|
||||||
|
std::process::exit(0);
|
||||||
|
},
|
||||||
|
_ = sigterm.recv() => {
|
||||||
|
log::info!("Received SIGTERM shutting down");
|
||||||
|
send.send(false)?;
|
||||||
|
std::process::exit(0);
|
||||||
|
},
|
||||||
|
_ = hangup.recv() => {
|
||||||
|
log::info!("Received SIGHUP reloading config.");
|
||||||
|
send.send(false)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> errors::Result {
|
||||||
|
let (send, recv) = watch::channel(true);
|
||||||
|
tokio::spawn(async move {
|
||||||
|
run(recv).await?;
|
||||||
|
return Ok(()) as errors::Result;
|
||||||
|
});
|
||||||
|
signal_select(send).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user