# gemi
A lightweight async Gemini protocol server framework built on Tokio and Rustls.
- Async handler functions with automatic argument extraction
- URL parameter routing with wildcards and sub-routers
- Shared application state via extractors
- TLS client certificate authentication
- Composable middleware (closures and traits)
- Built-in request tracing
- Static file serving with directory listings
- Gemtext document builder
- Graceful shutdown support
## Quick Start
```rust
use gemi::{EndpointExt, GeminiConfig, GeminiResponse, GeminiRouter, GeminiServer};
#[tokio::main]
async fn main() {
let mut router = GeminiRouter::default();
router.add_route("/", hello).unwrap();
let app = router.with_state(());
let server = GeminiServer::new(app, "certs/cert.der", "certs/key.der",
GeminiConfig::new("localhost")).unwrap();
server.serve().await.unwrap();
}
async fn hello() -> impl Into<GeminiResponse> {
"Hello, Gemini!"
}
```
## TLS Certificates
Gemini requires TLS. Generate a self-signed certificate for development:
```sh
mkdir -p certs
openssl genpkey -algorithm ed25519 -outform DER -out certs/key.der
openssl req -new -x509 -key certs/key.der -keyform DER \
-out certs/cert.der -outform DER \
-days 3650 -subj '/CN=localhost'
```
PKCS#1 (RSA), PKCS#8, and SEC1 (EC) key formats are all supported.
## Examples
The `examples/` directory covers routing, shared state, input prompts,
middleware, static file serving, client certificate auth, graceful shutdown,
and tracing. Run any of them with:
```sh
cargo run --example hello_gemini
```
## License
MIT