forked from cadey/maj
79 lines
2.3 KiB
Rust
79 lines
2.3 KiB
Rust
|
use std::fs::File;
|
||
|
use std::io::{self, BufReader};
|
||
|
use std::path::{Path, PathBuf};
|
||
|
use structopt::StructOpt;
|
||
|
use tokio_rustls::rustls::internal::pemfile::{certs, rsa_private_keys};
|
||
|
use tokio_rustls::rustls::{Certificate, NoClientAuth, PrivateKey, ServerConfig};
|
||
|
|
||
|
#[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,
|
||
|
}
|
||
|
|
||
|
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>> {
|
||
|
rsa_private_keys(&mut BufReader::new(File::open(path)?))
|
||
|
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid key"))
|
||
|
}
|
||
|
|
||
|
#[tokio::main]
|
||
|
async fn main() -> Result<(), maj::server::Error> {
|
||
|
pretty_env_logger::init();
|
||
|
let opts = Options::from_args();
|
||
|
let certs = load_certs(&opts.cert)?;
|
||
|
let mut keys = load_keys(&opts.key)?;
|
||
|
|
||
|
let mut config = ServerConfig::new(NoClientAuth::new());
|
||
|
config
|
||
|
.set_single_cert(certs, keys.remove(0))
|
||
|
.map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err))?;
|
||
|
|
||
|
maj::server::serve(Handler{}, config, opts.host, opts.port).await?;
|
||
|
|
||
|
Ok(())
|
||
|
}
|
||
|
|
||
|
struct Handler {}
|
||
|
|
||
|
fn index() -> Result<maj::Response, maj::server::Error> {
|
||
|
let msg = include_bytes!("../../majc/src/help.gmi");
|
||
|
|
||
|
Ok(maj::Response {
|
||
|
status: maj::StatusCode::Success,
|
||
|
meta: "text/gemini".to_string(),
|
||
|
body: msg.to_vec(),
|
||
|
})
|
||
|
}
|
||
|
|
||
|
#[async_trait::async_trait]
|
||
|
impl maj::server::Handler for Handler {
|
||
|
async fn handle(&self, r: maj::server::Request) -> Result<maj::Response, maj::server::Error> {
|
||
|
match r.url.path() {
|
||
|
"/" | "" => index(),
|
||
|
_ => Ok(maj::Response {
|
||
|
status: maj::StatusCode::NotFound,
|
||
|
meta: format!("{} not found", r.url),
|
||
|
body: vec![],
|
||
|
}),
|
||
|
}
|
||
|
}
|
||
|
}
|