🦊 Fluffer
Fluffer is an experimental crate that aims to make writing Gemini apps fun and easy.
🗼 Design
Similar to Axum, Fluffer routes are generic functions that
can return anything that implements the [GemBytes] trait.
There are some helpful implementations out of the box, so
please consult [GemBytes] and [Fluff] while you
experiment.
Also, this crate has a lot of examples for you to check out. Including a dice roller app.
Here is a basic example of a Fluffer app.
use ;
async
💎 GemBytes
The [GemBytes] trait returns a Gemini byte response, which
is formatted like this:
<STATUS><SPACE><META>\r\n<CONTENT>
Note: you must include the <SPACE> character, even if
<META> is blank.
To implement [GemBytes] on a type is to decide which
Gemini response is appropriate for it.
For example: it is sensible to represent some mime-ambiguous data as a successful Gemtext response so it can be read in a client.
use ;
📜 Certificates
Servers
Fluffer looks for the files ./key.pem (private) and
./cert.pem (public) at runtime. If they can't be located,
a prompt appears to generate a keypair interactively.
There's currently no way to define an alternate path to your pem files.
Clients
There are a few helpful certificate functions implemented on
[Context].
🥴 Parameters and Input
Queries in Gemini aren't one-to-one with HTTP.
Gemini clients tend to consider the entire query line to be a user's input. As such, they discard any queries you may have included in a link.
In other words, /?p=20 often becomes /?user%20input.
This is a problem for apps like search engines, which may want to include filters and pagination in each request alongside a user's search query.
To simplify the problem, Fluffer encourages you to use the
whole query as input, and [matchit]'s route parameters for
everything else.
Input
To get a user's input to a route, call [Context::input].
This returns the whole query line percent-decoded.
default
.route
.run
.await
.unwrap
Parameters
To access a parameter, you must declare it first in the path string. Referencing an undefined parameter causes the connection's thread to panic.
default
.route
.run
.await
.unwrap
If you're unfamiliar with matchit patterns, here's a couple of examples:
"/owo/:a/:b"defines parametersaandb, e.g:/owo/thisisa/thisisb"/page=:n/filter=:fdefines the parametern, e.g:/page=20/filter=date.
Things to keep in mind:
- Every parameter must be included in your url for the route to be found.
- Be careful where you define your parameters. It's possible to consume requests intended for a different route.
- It's more flexible to represent complex expressions as a single parameter, which you parse manually inside the route function.
📚 Helpful Resources
📋 Todo
- Async for route functions
- Switch to openssl
- Add peer certificate to context
- Spawn threads
- User-defined data
- Titan support