Added Reload on SIGHUP

This commit is contained in:
int 80h
2021-12-29 22:40:01 -05:00
parent f7429f3ad6
commit 0f07e7c2be
9 changed files with 168 additions and 112 deletions

2
Cargo.lock generated
View File

@@ -186,7 +186,7 @@ dependencies = [
[[package]]
name = "gemserv"
version = "0.6.2"
version = "0.6.3"
dependencies = [
"futures-util",
"log",

View File

@@ -1,6 +1,6 @@
[package]
name = "gemserv"
version = "0.6.2"
version = "0.6.3"
authors = ["int 80h <int@80h.dev>"]
edition = "2018"
description = "A gemini server"

13
README
View File

@@ -10,21 +10,26 @@ A gemini server written in rust.
- Reverse proxy
- Redirect
- SCGI
- Reload config on SIGHUP
## Installation and running
To run either run "cargo run /path/to/config" or if no configuration is
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
## Install from docker
### Install from docker
docker pull 080h/gemserv
## Build from source:
### Build from source:
- Clone the repo
- 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
- Run './target/release/gemserv config.toml'
### Init scripts
## Init scripts
In the init-scripts directory there's OpenRC(Courtesy of Tastytea) and systemd
service files.

View File

@@ -1,7 +1,7 @@
use tokio::fs::{self, File};
use tokio::io::{self, BufReader, AsyncWrite, AsyncBufReadExt};
use std::os::unix::fs::PermissionsExt;
use std::path::{Path, PathBuf};
use tokio::fs::{self, File};
use tokio::io::{self, AsyncBufReadExt, AsyncWrite, BufReader};
use url::Url;
#[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<()> {
let fd = File::open(path).await?;
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 {
let len = {
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);
}
futures_util::future::poll_fn(|ctx| {
std::pin::Pin::new(&mut con.stream).poll_shutdown(ctx)
})
futures_util::future::poll_fn(|ctx| std::pin::Pin::new(&mut con.stream).poll_shutdown(ctx))
.await?;
Ok(())
}
@@ -202,7 +201,7 @@ pub async fn handle_connection(mut con: conn::Connection, url: url::Url) -> Resu
return Ok(());
}
}
},
}
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 {
Ok(c) => {
con.send_body(Status::Success, Some(&mime), Some(c))
.await?;
con.send_body(Status::Success, Some(&mime), Some(c)).await?;
logger::logger(con.peer_addr, Status::Success, url.as_str());
}
Err(e) => {
println!("{}", e);
con.send_status(Status::NotFound, None)
.await?;
con.send_status(Status::NotFound, None).await?;
logger::logger(con.peer_addr, Status::NotFound, url.as_str());
}
}
} else {
let dir = gen_dir_list(path, &url).await?;
con.send_body(Status::Success, Some(&mime), Some(dir))

View File

@@ -3,9 +3,9 @@ extern crate toml;
use crate::lib::errors;
use std::collections::HashMap;
use std::env;
use std::path;
use std::net;
use std::net::ToSocketAddrs;
use std::path;
use tokio::fs;
use tokio::io;
@@ -91,7 +91,11 @@ impl Config {
} else if config.host.is_some() && config.port.is_some() {
let mut addr: Vec<std::net::SocketAddr> = Vec::new();
addr.push(
format!("{}:{}", &config.host.to_owned().unwrap(), &config.port.unwrap())
format!(
"{}:{}",
&config.host.to_owned().unwrap(),
&config.port.unwrap()
)
.to_socket_addrs()?
.next()
.ok_or_else(|| io::Error::from(io::ErrorKind::AddrNotAvailable))?,

View File

@@ -1,6 +1,7 @@
#![allow(unreachable_code)]
use tokio::io::AsyncReadExt;
use tokio::net::TcpListener;
use tokio::sync::watch::Receiver;
use tokio_rustls::server::TlsStream;
use tokio_rustls::TlsAcceptor;
@@ -71,15 +72,21 @@ impl Server {
self,
cmap: HashMap<String, config::ServerCfg>,
handler: impl Handler + 'static + Copy,
shutdown: Receiver<bool>,
) -> Result {
for listen in self.listener {
let cmap = cmap.clone();
let listen = Arc::new(listen);
let acceptor = Arc::new(self.acceptor.clone());
let mut shutdown = shutdown.clone();
tokio::spawn(async move {
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 acceptor = acceptor.clone();
let cmap = cmap.clone();
@@ -121,15 +128,14 @@ impl Server {
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(())
}
}

View File

@@ -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(())
}

View File

@@ -17,8 +17,11 @@ use lib::status;
use lib::tls::{self, tls_acceptor_conf};
use lib::util;
#[tokio::main]
async fn main() -> errors::Result {
use tokio::signal::unix;
use tokio::sync::watch;
async fn run(mut recv: watch::Receiver<bool>) -> errors::Result {
loop {
let cfg = match config::Config::new().await {
Ok(c) => c,
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();
println!("Serving {} vhosts", cfg.server.len());
log::info!("Serving {} vhosts", cfg.server.len());
let mut addr: Vec<std::net::SocketAddr> = Vec::new();
if let Some(i) = &cfg.interface {
@@ -42,10 +48,46 @@ async fn main() -> errors::Result {
.serve(
cmap,
server::force_boxed(con_handler::handle_connection),
recv.clone(),
)
.await
{
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(())
}