2020-07-27 23:49:39 +00:00
|
|
|
use async_std::task;
|
2020-07-28 01:03:50 +00:00
|
|
|
use rustls::{
|
2020-08-01 22:51:14 +00:00
|
|
|
internal::pemfile::{certs, pkcs8_private_keys},
|
2020-07-28 01:03:50 +00:00
|
|
|
AllowAnyAnonymousOrAuthenticatedClient, Certificate, PrivateKey, RootCertStore, ServerConfig,
|
|
|
|
};
|
2020-08-01 20:47:34 +00:00
|
|
|
use std::{
|
|
|
|
fs::File,
|
|
|
|
io::{self, BufReader},
|
|
|
|
path::{Path, PathBuf},
|
|
|
|
sync::Arc,
|
2020-08-02 02:42:44 +00:00
|
|
|
thread,
|
2020-08-01 20:47:34 +00:00
|
|
|
};
|
2020-07-26 00:16:07 +00:00
|
|
|
use structopt::StructOpt;
|
|
|
|
|
2020-08-02 02:42:44 +00:00
|
|
|
mod http;
|
|
|
|
mod server;
|
|
|
|
|
2020-07-26 00:16:07 +00:00
|
|
|
#[derive(StructOpt, Debug)]
|
|
|
|
struct Options {
|
|
|
|
/// host to listen on
|
|
|
|
#[structopt(short = "H", long, env = "HOST", default_value = "0.0.0.0")]
|
|
|
|
host: String,
|
|
|
|
|
|
|
|
/// port to listen on
|
|
|
|
#[structopt(short = "p", long, env = "PORT", default_value = "1965")]
|
|
|
|
port: u16,
|
|
|
|
|
|
|
|
/// cert file
|
|
|
|
#[structopt(short = "c", long = "cert", env = "CERT_FILE")]
|
|
|
|
cert: PathBuf,
|
|
|
|
|
|
|
|
/// key file
|
|
|
|
#[structopt(short = "k", long = "key", env = "KEY_FILE")]
|
|
|
|
key: PathBuf,
|
2020-07-26 12:21:02 +00:00
|
|
|
|
2020-07-31 17:13:51 +00:00
|
|
|
/// static path
|
2020-07-31 17:38:33 +00:00
|
|
|
#[structopt(short = "s", long, env = "STATIC_PATH", default_value = "./static")]
|
2020-07-31 17:13:51 +00:00
|
|
|
static_path: PathBuf,
|
|
|
|
|
2020-07-26 12:21:02 +00:00
|
|
|
/// server hostname
|
|
|
|
#[structopt(
|
|
|
|
long = "hostname",
|
|
|
|
env = "SERVER_HOSTNAME",
|
2020-08-01 20:47:34 +00:00
|
|
|
default_value = "cetacean.club"
|
2020-07-26 12:21:02 +00:00
|
|
|
)]
|
|
|
|
hostname: String,
|
2020-08-02 02:42:44 +00:00
|
|
|
|
|
|
|
/// HTTP port
|
|
|
|
#[structopt(long, default_value="34587")]
|
|
|
|
http_port: u16,
|
2020-07-26 00:16:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn load_certs(path: &Path) -> io::Result<Vec<Certificate>> {
|
|
|
|
certs(&mut BufReader::new(File::open(path)?))
|
|
|
|
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid cert"))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn load_keys(path: &Path) -> io::Result<Vec<PrivateKey>> {
|
2020-08-01 21:55:08 +00:00
|
|
|
pkcs8_private_keys(&mut BufReader::new(File::open(path)?))
|
2020-07-26 00:16:07 +00:00
|
|
|
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid key"))
|
|
|
|
}
|
|
|
|
|
2020-07-27 23:49:39 +00:00
|
|
|
fn main() -> Result<(), maj::server::Error> {
|
2020-07-31 17:13:51 +00:00
|
|
|
env_logger::init();
|
2020-07-26 00:16:07 +00:00
|
|
|
let opts = Options::from_args();
|
2020-08-01 21:55:08 +00:00
|
|
|
let certs = load_certs(&opts.cert).unwrap();
|
|
|
|
let mut keys = load_keys(&opts.key).unwrap();
|
2020-07-26 00:16:07 +00:00
|
|
|
|
2020-07-28 00:50:42 +00:00
|
|
|
log::info!(
|
|
|
|
"serving gemini://{} on {}:{}",
|
|
|
|
opts.hostname,
|
|
|
|
opts.host,
|
|
|
|
opts.port
|
|
|
|
);
|
2020-07-26 12:21:02 +00:00
|
|
|
|
2020-07-28 01:03:50 +00:00
|
|
|
let mut config = ServerConfig::new(AllowAnyAnonymousOrAuthenticatedClient::new(
|
|
|
|
RootCertStore::empty(),
|
|
|
|
));
|
2020-07-26 00:16:07 +00:00
|
|
|
config
|
|
|
|
.set_single_cert(certs, keys.remove(0))
|
|
|
|
.map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err))?;
|
|
|
|
|
2020-08-02 02:42:44 +00:00
|
|
|
let h = Arc::new(server::Handler {
|
|
|
|
hostname: opts.hostname,
|
|
|
|
files: maj::server::files::Handler::new(opts.static_path),
|
|
|
|
});
|
|
|
|
|
|
|
|
{
|
|
|
|
let port = opts.http_port.clone();
|
|
|
|
let h = h.clone();
|
|
|
|
thread::spawn(move || http::run(h.clone(), port));
|
|
|
|
}
|
|
|
|
|
2020-07-27 23:49:39 +00:00
|
|
|
task::block_on(maj::server::serve(
|
2020-08-02 02:42:44 +00:00
|
|
|
h.clone(),
|
2020-07-26 12:21:02 +00:00
|
|
|
config,
|
|
|
|
opts.host,
|
|
|
|
opts.port,
|
2020-07-27 23:49:39 +00:00
|
|
|
))?;
|
2020-07-26 00:16:07 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2020-08-02 02:42:44 +00:00
|
|
|
// And finally, include the generated code for templates and static files.
|
|
|
|
include!(concat!(env!("OUT_DIR"), "/templates.rs"));
|