Added Reload on SIGHUP
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -186,7 +186,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gemserv"
|
||||
version = "0.6.2"
|
||||
version = "0.6.3"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"log",
|
||||
|
||||
@@ -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
13
README
@@ -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.
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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))?,
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
|
||||
50
src/main.rs
50
src/main.rs
@@ -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(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user